-- DragonWishM
-- Created by chengb Feb/5/2015
-- 神龙许愿模块

module("DragonWishM", package.seeall);

-- 许愿需求物品
local wishItemInfo;

-- 当前层刷出的龙珠数量
local layerCount = 0;

-- 配置表
local wishConfig = {};
local rules = {};

-- 内部函数声明
local addWishTimes;
local clearWishOptions;
local updateOptionTimes;
local updateDailyOptionTimes;
local whenHillDoneDry;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下dungeon_action信息表
    local dragon_wish_CSV = get_dragon_wish_CSV();
    for i = 1, #dragon_wish_CSV do
        wishConfig[dragon_wish_CSV[i].id] = dragon_wish_CSV[i];
    end

    dragon_wish_CSV = {};
end

-- 初始化
function init()
    if not _init then
        loadCsv();

        -- 载入所有的规则处理子模块
        rules = LOAD_PATH("game/logic/module/dragon_wish");

        -- 获取神龙许愿需求物品
        wishItemInfo = FormulaM.invoke("DRAGON_WISH_ITEM");
    end

    -- 关注玩家获得物品
    EventMgr.removeAll("DragonWishM");
    EventMgr.register("DragonWishM", event.BONUS_ITEM, function(args)
        -- 不是需求物品，不处理
        if args["classId"] ~= wishItemInfo["class_id"] then
            return;
        end

        -- 获取奖励描述
        local desc = args.desc;

        -- 尝试触发神龙许愿
        triggerEvent(desc);
    end);

    -- 矿山枯竭了
    EventMgr.register("DragonWishM", event.MINE_HILL_BONE_DRY, whenHillDoneDry);
end

-- 检索
function query(id, path)
    local m = wishConfig[id];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 获取所有的选项
function getAllOptions()
    local ret = table.keys(wishConfig);
    table.sort(ret);
    return ret;
end

-- 根据规则获取选项
function getOptionByRule(rule)
    local optionList = table.values(wishConfig);
    for _, info in pairs(optionList) do
        if info.rule == rule then
            return info;
        end
    end
    return nil;
end

-- 判断选项能否抽取
function canFetchWish(id)
    local rule = query(id, "rule");
    local mod = rules[rule];

    if mod and mod.canFetchWish then
        return mod.canFetchWish(id);
    end

    local times = getOptionTimesById(id);
    local maxTimes = query(id, "times");

    if maxTimes ~= NUMBER_INFINITY and maxTimes <= times then
        return false;
    end

    return true;
end

-- 触发神龙许愿
function triggerEvent(desc)
    -- 条件没达成，不处理
    if not canTriggerEvent() then
        return;
    end

    -- 先获取下当前的选项
    local options = getWishOptions();
    -- 如果当前还没选项就抽取一下
    if type(options) ~= "table" or #options <= 0 then
        -- 抽取许愿选项
        options = FormulaM.invoke("CALC_DRAGON_WISH_OPTIONS", ME.user);
        local wishInfo = ME.user.dbase:query("wish_info", {});
        wishInfo["options"] = options;
        ME.user.dbase:set("wish_info", wishInfo);
    end

    -- 是否已经收齐了龙珠
    local isFull = ItemM.getAmount(ME.user, wishItemInfo["class_id"]) >= wishItemInfo["count"];

    -- 通知打开神龙许愿界面
    EventMgr.fire(event.WISH_TRIGGER, { ["options"] = options,
        ["isOpenForm"] = isFull, ["desc"] = desc, });
end

-- 判断能否触发许愿
function canTriggerEvent()
    -- 不在地牢中，不能触发
    if not DungeonM.isInDungeon() then
        return false;
    end

    -- 1.当数量达到1个时提前触发生成选项信息（只要获得龙珠就触发选项）
    -- 2.当数量达到N个时，通知打开神龙许愿界面
    if ItemM.getAmount(ME.user, wishItemInfo["class_id"]) < 1 then
        -- 道具数量没达到要求
        return false;
    end

    return true;
end

-- 判断能否许愿
function canDoWish(index)
    local options = getWishOptions();
    if type(index) ~= "number" or type(options) ~= "table" or index > #options  then
        -- 选项不存在
        return false;
    end

    if ItemM.getAmount(ME.user, wishItemInfo["class_id"]) < wishItemInfo["count"] then
        -- 道具数量不足
        return false;
    end

    return true;
end

----------------------
-- 执行许愿
-- @function [parent=#src.game.logic.module.DragonWishM] doWish
-- @param index   选择的选项索引
function doWish(index)
    -- 经判断，不能许愿
    if true ~= canDoWish(index) then
        return false;
    end

    local options = getWishOptions();
    if not options then
        -- 选项尚未生成
        return false;
    end

    local optionInfo = options[index];
    if not optionInfo then
        -- 选项不存在
        return false;
    end

    -- 扣除道具
    if not ItemM.costAmount(ME.user, wishItemInfo["class_id"], wishItemInfo["count"]) then
        trace("DrageonWishM", "扣除许愿道具失败了。");
        return false;
    end

    trace("DrageonWishM", "剩余龙珠数量：%d", ItemM.getAmount(ME.user, wishItemInfo["class_id"]));

    -- 交给子模块处理需要事宜
    local rule = query(optionInfo["id"], "rule");
    local mod = rules[rule];

    local log = string.format("神龙许愿：%s", tableToString(optionInfo));
    DungeonLogM.addLog(log);

    mod.doWish(optionInfo);

    -- 清除许愿选项
    clearWishOptions();

    -- 更新选项出现的次数
    updateOptionTimes(optionInfo.id);

    -- 更新每日许愿次数
    updateDailyOptionTimes(optionInfo.id);

    -- 抛出许愿事件
    EventMgr.fire(event.WISH_DONE, { ["bonus"] = optionInfo.bonus, });
    return true;
end

-- 抽取许愿项信息
function fetchOption(id)
    local mod = rules[query(id, "rule")];

    if mod.fetchOption then
        return mod.fetchOption(id);
    end

    -- 默认仅包含id
    return { ["id"] = id, };
end

-- 获取已许愿次数
function getWishTimes()
    local wishInfo = ME.user.dbase:query("wish_info");
    if not wishInfo or not wishInfo["times"] then
        return 0;
    end

    return wishInfo["times"];
end

-- 获取许愿选项
function getWishOptions()
    local wishInfo = ME.user.dbase:query("wish_info", {});
    return wishInfo["options"];
end

-- 获取某个选项出现的次数
function getOptionTimesById(id)
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local optionTimes = wishInfo["option_times"] or {};
    if not optionTimes[id] then
        return 0;
    end
    return optionTimes[id];
end

-- 清除许愿选项
function clearWishOptions()
    local wishInfo = ME.user.dbase:query("wish_info", {});
    wishInfo["options"] = nil;
end

-- 累积许愿次数
function addWishTimes()
    local wishInfo = ME.user.dbase:query("wish_info", {});
    wishInfo["times"] = getWishTimes() + 1;

    trace("DragonWishM", "当前神龙许愿次数：%d", wishInfo["times"]);
end

-- 更新选项被选择的次数
function updateOptionTimes(id)
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local optionTimes = wishInfo["option_times"] or {};

    optionTimes[id] = optionTimes[id] or 0;
    optionTimes[id] = optionTimes[id] + 1;
    wishInfo["option_times"] = optionTimes;
    ME.user.dbase:set("wish_info", wishInfo);

    printTable(optionTimes, "神龙许愿各选项出现的次数");
end

----------------------------------
-- 获取神龙许愿选项的描述
-- @param id   选项id
function getOptionDesc(id)
    return query(id, "options_text");
end

-- 获取许愿需要的个数
function getWishNeedCount()
    return wishItemInfo["count"];
end

-- 获取神龙许愿已经拥有的物品数量
function getWishItemCount()
    return ItemM.getAmount(ME.user, wishItemInfo["class_id"]);
end

-- 获取当前层中存在的龙珠数量加上已拥有的龙珠数量的总和
function getCurLayerWishCount()
    local haveCount = getWishItemCount();
    return haveCount + layerCount;
end

-- 获取当前层刷出龙珠数量
function getLayerCount()
    layerCount = layerCount or 0;
    return layerCount;
end

-- 设置当前层刷出的龙珠数量
function setLayerCount(number)
    if not layerCount then layerCount = 0; end
    layerCount = number;
end

-- 是否是神龙许愿所需的物品
function isWishItem(classId)
    if wishItemInfo["class_id"] == classId then
        return true;
    end
    return false;
end

-- 领取神龙许愿彩蛋奖励
function takeBuildingBonus(pos, class)
    if type(UnrealDungeonM.getUnrealId()) ~= "number" then
        -- 玩家不在夹层中
        return false;
    end

    local grid = DungeonM.getGridByPos(pos);

    if grid.class ~= class then
        -- 玩家尝试领取非法奖励
        return false;
    end

    if grid.type ~= GRID_TYPE_UNREAL_SPECIAL then
        -- 不是神龙许愿彩蛋格子
        return false;
    end

    if grid.state == GRID_STATE_DISABLE then
        -- 格子失效了
        return false;
    end

    local bonus = FormulaM.invoke("CALC_DRAGON_WISH_BUILDING_BONUS", class);

    -- 猴子奖励需要扣除10金币
    if class == 184 then
        local costList = FormulaM.invoke("CALC_DRAGON_WISH_BUILDING_BONUS", "cost_money");
        for _, perCost in pairs(costList)do
            if perCost[1] == 2 then
                ME.user:costAttrib(perCost[2], perCost[3]);
            end
        end
    end

    -- 植物需要使用剪刀
    if class == 181 or class == 182 then
        -- 植物，需要使用剪刀
        if ItemM.getAmount(ME.user, 7157) <= 0 then
            -- 没有剪刀
            return false;
        end

        PropertyM.costProperty(ME.user, 7157);
    end

    for _, perBonus in pairs(bonus) do
        -- 奖励
        BonusM.doBonus(perBonus, "dragon_wish_bonus");
    end

    -- 改变状态
    grid:changeState(GRID_STATE_DISABLE);

    return true;
end

-- 是否许过愿
function hasMadeWish()
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local optionTimes = wishInfo["option_times"];
    -- 没有许愿信息就是没许过愿望
    if optionTimes == nil then
        return false;
    else
        return true;
    end
end

-- 获取某个选项的每日许愿次数
function getDailyOptionTimesById(id)
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local DailyOptionTimes = wishInfo["daily_option_times"] or {};
    if not DailyOptionTimes[id] then
        return 0;
    end
    return DailyOptionTimes[id];
end

-- 更新每日许愿次数
function updateDailyOptionTimes(id)
    -- 不限制次数的就不用记了
    local dailyTimesLimit = query(id, "daily_times");
    if dailyTimesLimit == NUMBER_INFINITY then
        return;
    end

    local wishInfo = ME.user.dbase:query("wish_info");
    if type(wishInfo) ~= "table" then
        return;
    end

    local DailyOptionTimes = wishInfo["daily_option_times"] or {};

    DailyOptionTimes[id] = DailyOptionTimes[id] or 0;
    DailyOptionTimes[id] = DailyOptionTimes[id] + 1;

    wishInfo["daily_option_times"] = DailyOptionTimes;
    ME.user.dbase:set("wish_info", wishInfo);
end


function isDiamondMineOver()
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local record = wishInfo["first_diamond_record"] or 0;

    -- 三个都挖完了就完了
    for i = 0, 2 do
        local b = bit.blshift(1, i);
        if bit.band(record, b) == 0 then
            return false;
        end
    end

    return true;
end

function getInvalidDiamond()
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local record = wishInfo["first_diamond_record"] or 0;

    -- 获得挖完的矿脉index
    local ret = {};
    for i = 0, 2 do
        local b = bit.blshift(1, i);
        if bit.band(record, b) > 0 then
            local index = FormulaM.invoke("GET_DIAMOND_HILL_RECORD", i, "pos");

            table.insert(ret, index);
        end
    end

    return ret;
end

whenHillDoneDry = function(params)
    -- 不是在神龙夹层不管
    if not UnrealDungeonM.isInUnreal() then
        return;
    end

    local unrealId = UnrealDungeonM.getUnrealId();
    if unrealId ~= 6 then
        return;
    end

    -- 记录挖完的位置
    local wishInfo = ME.user.dbase:query("wish_info", {});
    local record = wishInfo["first_diamond_record"] or 0;

    local index = FormulaM.invoke("GET_DIAMOND_HILL_RECORD", params.pos, "index");

    local b = bit.blshift(1, index);
    record = bit.bor(record, b);

    wishInfo["first_diamond_record"] = record;

    ME.user.dbase:set("wish_info", wishInfo);
end
